// tube_detector_bindings.dart
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';

/// C 语言结构体定义，用于与原生代码交互
/// 对应 C++ 中的 TubeLocation 结构体
base class TubeLocationFFI extends Struct {
  @Int32()
  external int x;

  ///< 试管中心点X坐标(像素)

  @Int32()
  external int y;

  ///< 试管中心点Y坐标(像素)

  @Int32()
  external int index;

  ///< 试管在架中的索引位置(0-based)

  @Bool()
  external bool hasTube;

  ///< 该位置是否存在试管
}

/// C 语言结构体定义，用于与原生代码交互
/// 对应 C++ 中的 DetectionResult 结构体
base class DetectionResultFFI extends Struct {
  external Pointer<TubeLocationFFI> rectangles;

  ///< 检测到的矩形轮廓中心点(无试管的孔位)
  @Int32()
  external int rectanglesCount;

  ///< 矩形数量

  external Pointer<TubeLocationFFI> circles;

  ///< 检测到的圆形中心点(所有试管孔位置)
  @Int32()
  external int circlesCount;

  ///< 圆形数量

  external Pointer<TubeLocationFFI> sortedTubes;

  ///< 按行列排序后的试管位置
  @Int32()
  external int sortedTubesCount;

  ///< 排序后试管数量

  external Pointer<Int32> tubeMatches;

  ///< 圆形位置到试管有无状态的匹配(-1表示无试管，其他表示有试管)
  @Int32()
  external int tubeMatchesCount;

  ///< 匹配结果数量

  external Pointer<TubeLocationFFI> tubesWithTube;

  ///< 有试管的坐标数组
  @Int32()
  external int tubesWithTubeCount;

  ///< 有试管的孔位数量
}

// =========================================================================
// Dart 数据类定义
// =========================================================================

/// Dart 端的试管位置信息类
/// 封装了从原生代码获取的试管位置数据
class TubeLocation {
  final int x;

  ///< 试管中心点X坐标(像素)
  final int y;

  ///< 试管中心点Y坐标(像素)
  final int index;

  ///< 试管在架中的索引位置(0-based)
  final bool hasTube;

  ///< 该位置是否存在试管

  /// 构造函数
  TubeLocation({
    required this.x,
    required this.y,
    required this.index,
    required this.hasTube,
  });

  @override
  String toString() {
    return 'TubeLocation(x: $x, y: $y, index: $index, hasTube: $hasTube)';
  }
}

/// Dart 端的检测结果类
/// 封装了从原生代码获取的单帧检测结果
class DetectionResult {
  final List<TubeLocation> rectangles;

  ///< 检测到的矩形轮廓中心点(无试管的孔位)
  final List<TubeLocation> circles;

  ///< 检测到的圆形中心点(所有试管孔位置)
  final List<TubeLocation> sortedTubes;

  ///< 按行列排序后的试管位置
  final List<int> tubeMatches;

  ///< 圆形位置到试管有无状态的匹配(-1表示无试管，其他表示有试管)
  final List<TubeLocation> tubesWithTube;

  ///< 有试管的坐标数组

  /// 构造函数
  DetectionResult({
    required this.rectangles,
    required this.circles,
    required this.sortedTubes,
    required this.tubeMatches,
    required this.tubesWithTube,
  });
}

// =========================================================================
// FFI 绑定类
// =========================================================================

/// 原生库绑定类
/// 负责加载动态链接库并提供原生函数的Dart接口
class TubeDetectorBindings {
  static DynamicLibrary? _library;

  ///< 动态链接库实例

  /// 获取动态链接库实例（单例模式）
  static DynamicLibrary get library {
    _library ??= _loadLibrary();
    return _library!;
  }

  /// 加载动态链接库
  /// 根据不同平台加载对应的库文件
  static DynamicLibrary _loadLibrary() {
    if (Platform.isWindows) {
      return DynamicLibrary.open('view.dll');

      ///< Windows平台加载view.dll
    }
    // else if (Platform.isLinux) {
    //   return DynamicLibrary.open('libview.so');

    //   ///< Linux平台加载libview.so
    // } else if (Platform.isMacOS) {
    //   return DynamicLibrary.open('libview.dylib');

    //   ///< macOS平台加载libview.dylib
    // }
    else {
      throw UnsupportedError('Platform not supported');

      ///< 不支持的平台抛出异常
    }
  }

  // =========================================================================
  // 原生函数绑定
  // =========================================================================
  /// 创建试管检测器实例
  /// @return 指向检测器实例的指针
  static final Pointer<Void> Function() createTubeDetector = library
      .lookup<NativeFunction<Pointer<Void> Function()>>('create_tube_detector')
      .asFunction();

  /// 销毁试管检测器实例
  /// @param detector 要销毁的检测器指针
  static final void Function(Pointer<Void>) destroyTubeDetector = library
      .lookup<NativeFunction<Void Function(Pointer<Void>)>>(
          'destroy_tube_detector')
      .asFunction();

  /// 初始化检测器
  /// @param detector 检测器指针
  /// @param cameraIndex 摄像头设备索引
  /// @return 初始化是否成功
  static final bool Function(Pointer<Void>, int) initializeDetector = library
      .lookup<NativeFunction<Bool Function(Pointer<Void>, Int32)>>(
          'initialize_detector')
      .asFunction();

  /// 开始检测流程
  /// @param detector 检测器指针
  /// @return 启动是否成功
  static final bool Function(Pointer<Void>) startDetection = library
      .lookup<NativeFunction<Bool Function(Pointer<Void>)>>('start_detection')
      .asFunction();

  /// 停止检测流程
  /// @param detector 检测器指针
  static final void Function(Pointer<Void>) stopDetection = library
      .lookup<NativeFunction<Void Function(Pointer<Void>)>>('stop_detection')
      .asFunction();

  /// 处理单帧图像
  /// @param detector 检测器指针
  /// @return 指向检测结果结构体的指针
  static final Pointer<DetectionResultFFI> Function(Pointer<Void>)
      processSingleFrame = library
          .lookup<
              NativeFunction<
                  Pointer<DetectionResultFFI> Function(
                      Pointer<Void>)>>('process_single_frame')
          .asFunction();

  /// 释放检测结果内存
  /// @param result 要释放的检测结果指针
  static final void Function(Pointer<DetectionResultFFI>) freeDetectionResult =
      library
          .lookup<NativeFunction<Void Function(Pointer<DetectionResultFFI>)>>(
              'free_detection_result')
          .asFunction();

  /// 获取当前试管状态
  /// @param detector 检测器指针
  /// @param count 输出参数，返回试管状态数量
  /// @return 指向试管状态数组的指针
  static final Pointer<TubeLocationFFI> Function(Pointer<Void>, Pointer<Int32>)
      getCurrentTubeStates = library
          .lookup<
              NativeFunction<
                  Pointer<TubeLocationFFI> Function(Pointer<Void>,
                      Pointer<Int32>)>>('get_current_tube_states')
          .asFunction();

  /// 释放试管状态内存
  /// @param states 要释放的试管状态指针
  static final void Function(Pointer<TubeLocationFFI>) freeTubeStates = library
      .lookup<NativeFunction<Void Function(Pointer<TubeLocationFFI>)>>(
          'free_tube_states')
      .asFunction();

  /// 设置调试模式
  /// @param detector 检测器指针
  /// @param enable 是否启用调试模式
  static final void Function(Pointer<Void>, bool) setDebugMode = library
      .lookup<NativeFunction<Void Function(Pointer<Void>, Bool)>>(
          'set_debug_mode')
      .asFunction();
}
